package plgigiel.behaviour.boid;

import pl.gigiel.behaviour.IBoid;
import pl.gigiel.behaviour.IBoidFeatures;
import pl.gigiel.behaviour.IEnvironment;
import pl.gigiel.behaviour.ISteerManager;
import pl.gigiel.behaviour.exception.BehaviourException;
import pl.gigiel.behaviour.util.Util;

import com.jme.math.Vector3f;

public class SimpleBoid implements IBoid {
	private IEnvironment environment;
	private ISteerManager steerManager;
	private IBoidFeatures features;
	private IBoidFeatures featuresNext;

	@Override
	public IEnvironment getEnvironment() {
		return environment;
	}

	@Override
	public void setEnvironment(IEnvironment environment) {
		this.environment = environment;
	}

	@Override
	public ISteerManager getSteerManager() {
		return steerManager;
	}

	@Override
	public void setSteerManager(ISteerManager steerManager) {
		this.steerManager = steerManager;
	}

	@Override
	public IBoidFeatures getFeatures() {
		return features.clone();
	}

	@Override
	public void setFeatures(IBoidFeatures features) {
		this.features = features.clone();
		this.featuresNext = features.clone();
	}

	@Override
	public void init() throws BehaviourException {
	}

	@Override
	public void prepare(float elapsed) throws BehaviourException {
		Vector3f steeringForce = getSteerManager().resultant(this, elapsed);
		if (Util.isEmpty(steeringForce) || elapsed == 0.0f) {
			return;
		}
		Vector3f velocity = calculatedVelocity(steeringForce, elapsed);
		velocity = limitedVelocity(velocity);
		Vector3f position = environment.calculatedPosition(this, elapsed, velocity);

		featuresNext.setVelocity(velocity);
		featuresNext.setPosition(position);
	}

	@Override
	public void perform() throws BehaviourException {
		features = featuresNext.clone();
	}

	private Vector3f calculatedVelocity(Vector3f force, float elapsed) {
		Vector3f velocity = features.getVelocity();
		Vector3f acceleration = force.divide(features.getMass());
		velocity.addLocal(acceleration.mult(elapsed));
		return velocity;
	}

	private Vector3f limitedVelocity(Vector3f velocity) {
		Vector3f result = Util.truncatedMutual(velocity, features.getSpeed());
		return result;
	}
}
